/**
 * Copyright (C) 2015-2018 IQIYI
 * All rights reserved.
 *
 * Author     : 王海斌
 * E-mail     : wanghaibin@qiyi.com
 * Version    :
 * Date       : Tue 18 Dec 2018 02:36:52 PM CST
 * Destription: 读取指定进程的 /proc/[pid]/stat 状态信息
 *
 */

#include <stdio.h>
#include <string>

bool ExecCmd(const char * cmd, std::string & out)
{
    FILE * fp = popen(cmd, "r");
    if(NULL==fp) {
        return false;
    }

    char line[2048] = {0};
    char* ptr = fgets(line, sizeof(line) - 1, fp);
    pclose(fp);
    if(NULL==ptr) {
        return false;
    }
    out = line;
    return true;
}

typedef struct ProcStatInfo
{
    int pid; //程序id
    char pname[256];                    //程序名
    char state;                         //状态
    int ppid;                           //父id
    int pgrp;                           //组id
    int session;                        //进程会话id
    int tty_nr;                         //进程控制终端
    int tpgid;                          //进程控制终端的前台进程组的ID
    unsigned int flags;                 //内核进程标记字
    unsigned long minflt;               //该任务不需要从硬盘拷数据而发生的缺页（次缺页）的次数
    unsigned long cminflt;              //累计的该任务的所有的waited-for进程曾经发生的次缺页的次数目
    unsigned long majflt;               //任务需要从硬盘拷数据而发生的缺页（主缺页）的次数
    unsigned long cmajflt;              //累计的该任务的所有的waited-for进程曾经发生的主缺页的次数目
    unsigned long utime;                //该任务在用户态运行的时间
    unsigned long stime;                //该任务在核心态运行的时间
    long cutime;                        //累计的该任务的所有的waited-for进程曾经在用户态运行的时间
    long cstime;                        //累计的该任务的所有的waited-for进程曾经在核心态运行的时间
    long priority;                      //表示进程的优先级
    long nice;                          //表示进程的nice值
    long num_threads;                   //表示进程的线程数量
    long itrealvalue;                   //由于计时间隔导致的下一个 SIGALRM 发送进程的时延
    unsigned long long starttime;       //表示进程的启动时间
    unsigned long vsize;                //该任务的虚拟地址空间大小
    long rss;                           //该任务当前驻留物理地址空间的大小
    unsigned long rsslim;               //该任务能驻留物理地址空间的最大值
    unsigned long startcode;            //该任务在虚拟地址空间的代码段的起始地址
    unsigned long endcode;              //该任务在虚拟地址空间的代码段的结束地址
    unsigned long startstack;           //该任务在虚拟地址空间的栈的结束地址
    unsigned long kstkesp;              //esp(32 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致
    unsigned long kstkeip;              //指向将要执行的指令的指针, EIP(32 位指令指针)的当前值
    unsigned long signal;               //
    unsigned long blocked;              //
    unsigned long sigignore;
    unsigned long sigcatch;
    unsigned long wchan;
    unsigned long nswap;
    unsigned long cnswap;
    int exit_signal;
    int processor;
    unsigned int rt_priority;
    unsigned int policy;
    unsigned long long delayacct_blkio_ticks;
    unsigned long guest_time;
    long cguest_time;
    unsigned long start_data;
    unsigned long end_data;
    unsigned long start_brk;
    unsigned long arg_start;
    unsigned long arg_end;
    unsigned long env_start;
    unsigned long env_end;
    unsigned long exit_code;

}ProcStatInfo;

void usage(char ** argv)
{
    printf("usage: %s pid\r\n", argv[0]);
}

int main(int argc, char *argv[])
{
    if(argc != 2) {
        usage(argv);
        return 0;
    }
    char cmd[128]={0};
    snprintf(cmd, sizeof(cmd)-1, "cat /proc/%s/stat", argv[1]);
    std::string out;
    ExecCmd(cmd, out);

    ProcStatInfo st;
    sscanf(out.c_str(), "%d %s %c %d %d %d %d %d %u"
            "%lu %lu %lu %lu %lu %lu %ld %ld"
            "%ld %ld %ld %ld %llu %lu %ld"
            "%lu %lu %lu %lu %lu %lu %lu"
            "%lu %lu %lu %lu %lu %lu %d %d"
            "%u %u %llu %lu %ld %lu"
            "%lu %lu %lu %lu %lu %lu %lu" ,
            &st.pid, st.pname, &st.state, &st.ppid, &st.pgrp, &st.session, &st.tty_nr, &st.tpgid, &st.flags,
            &st.minflt, &st.cminflt, &st.majflt, &st.cmajflt, &st.utime, &st.stime, &st.cutime, &st.cstime,
            &st.priority, &st.nice, &st.num_threads, &st.itrealvalue, &st.starttime, &st.vsize, &st.rss,
            &st.rsslim, &st.startcode, &st.endcode, &st.startstack, &st.kstkesp, &st.kstkeip, &st.signal,
            &st.blocked, &st.sigignore, &st.sigcatch, &st.wchan, &st.nswap, &st.cnswap, &st.exit_signal, &st.processor,
            &st.rt_priority, &st.policy,&st.delayacct_blkio_ticks, &st.guest_time, &st.cguest_time, &st.start_data,
            &st.end_data, &st.start_brk, &st.arg_start, &st.arg_end, &st.env_start, &st.env_end, &st.exit_code
        );
    printf("pid=%d name=%s time=%llu, rss=%ld\r\n", st.pid, st.pname, st.starttime, st.rss);
    return 0;
}
